package com.leenmvc.core.utils;



import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.LinkedList;

/**
 * 单路1078单路线程
 */
public class HandlerVideo {

    private final static Logger logger = LoggerFactory.getLogger(HandlerVideo.class);

    /**
     * 接收端口
     */
    private Integer port;

    /**
     * 推送地址
     */
    private String rtmp;

    public HandlerVideo(Integer port, String rtmp) {
        this.port = port;
        this.rtmp = rtmp;
    }

//    @Override
//    public void run() {
//        try {
//            // 接受JT1078协议数据并将处理过后的数据导入指定容器
//            ServerSocket server = new ServerSocket(this.port, 100);
//            while (true) {
//                Socket conn = server.accept();
//                String uuid = UUID.randomUUID().toString().replace("-", "");
//                String rtmpUrl = this.rtmp + uuid;
//                //获取系统名称
//                String osName = System.getProperty("os.name");
//                String path = "";
//                if (osName.toLowerCase().contains("windows")){
//                    path = "/plug/ffmpeg/bin/ffmpeg.exe";
//                }else{
//                    path = "/plug/ffmpeg_linux/ffmpeg";
//                }
//                String command = (userDir + path+" -f h264 -i - -flvflags no_duration_filesize -probesize 512 -analyzeduration 100 -f flv " + rtmpUrl);
//                Process process = Runtime.getRuntime().exec(command);
//                new Reader(process.getErrorStream()).start();
//                Publisher videoPublisher = new VideoPublisher(process);
//                Publisher audioPublisher = new AudioPublisher(process);
//                videoPublisher.start();
//                audioPublisher.start();
//                new HandlerSocket(conn, videoPublisher, audioPublisher).start();
//
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

    class HandlerSocket extends Thread {

        /**
         * 用来控制当前线程是否结束
         */
        private boolean over = false;

        public boolean getOver() {
            return over;
        }

        public void setOver(boolean over) {
            this.over = over;
        }

        private Socket conn;
        private Publisher videoPublisher;
        private Publisher audioPublisher;

        public HandlerSocket(Socket conn, Publisher videoPublisher, Publisher audioPublisher) {
            this.videoPublisher = videoPublisher;
            this.audioPublisher = audioPublisher;
            this.conn = conn;
        }

        /**
         * 处理JT1078协议的数据
         *
         * @throws IOException
         */
//        public void run() {
//            InputStream input = null;
//            try {
//                input = conn.getInputStream();
//                int len = -1;
//                byte[] block = new byte[1024];
//                Jtt1078Decoder decoder = new Jtt1078Decoder();
//                a:
//                while (true) {
//                    try {
//                        len = input.read(block);
//                        if (len == -1) break;
//                        decoder.write(block, 0, len);
//                        b:
//                        while (true) {
//                            if (this.over) break a;
//                            Packet p = decoder.decode();
//                            if (p == null) break;
//                            int lengthOffset = 28;
//                            int dataType = (p.seek(15).nextByte() >> 4) & 0x0f;
//                            // 透传数据类型：0100，没有后面的时间以及Last I Frame Interval和Last Frame Interval字段
//                            if (dataType == 0x04) lengthOffset = 28 - 8 - 2 - 2;
//                            else if (dataType == 0x03) lengthOffset = 28 - 4;
//                            // FFMpegManager.getInstance().feed(publisherId, packet.seek(lengthOffset + 2).nextBytes());
//                            if (dataType == 0x00 || dataType == 0x01 || dataType == 0x02) {
//                                videoPublisher.publish(p.seek(lengthOffset + 2).nextBytes());
//                            } else {
//                                audioPublisher.publish(p.seek(lengthOffset + 2).nextBytes());
//                            }
//                        }
//                    } catch (Exception e) {
//                        videoPublisher.setUp(false);
//                        audioPublisher.setUp(false);
//                        videoPublisher.publish(new byte[]{1});
//                        audioPublisher.publish(new byte[]{0});
//                        e.printStackTrace();
//                        break;
//                    }
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            try {
//                input.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
    }

    /**
     * Reader输出Runtime.getRuntime().exec 的运行结果
     */
    public static class Reader extends Thread {
        InputStream stdout = null;

        public Reader(InputStream is) {
            this.stdout = is;
        }

        public void run() {
            int len = -1;
            byte[] block = new byte[512];
            try {
                while ((len = stdout.read(block)) > -1) {
                    logger.info(new String(block, 0, len));
                }

            } catch (Exception ex) {
                ex.printStackTrace();
            }

        }
    }

    /**
     * 中转方法中转转码后的字节码数组
     */
    class Publisher extends Thread {
        /**
         * 这个变量控制当前线程是否结束掉这个子线程
         */
        protected boolean up;

        public void setUp(boolean up) {
            this.up = up;
        }

        public boolean getUp() {
            return up;
        }

        Object lock = new Object();
        LinkedList<byte[]> messages = new LinkedList();

        public void publish(byte[] msg) {
            synchronized (lock) {
                messages.add(msg);
                lock.notify();
            }
        }

        public byte[] peek(Publisher publisher) {
            byte[] msg = null;
            synchronized (lock) {
                while (messages.size() == 0 && publisher.up) try {
                    lock.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                msg = messages.removeFirst();
            }
            return msg;
        }

        public FileOutputStream open(String fname) {
            try {
                return new FileOutputStream(fname);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    /**
     * 异步线程将转码之后的内容（视频）写入到本地文件中
     * 如果将该部分的数据通过输出流输出那么就解决了
     */
    class VideoPublisher extends Publisher {

        private Process process;

        public VideoPublisher(Process process) {
            this.process = process;
            this.up = true;
        }

        public void run() {
            OutputStream outputStream = process.getOutputStream();
            while (!this.isInterrupted() && this.up) {

                try {
                    byte[] msg = peek(this);
                    outputStream.write(msg);
                    outputStream.flush();
                } catch (Exception ex) {
                    ex.printStackTrace();
                    break;
                }
            }

        }
    }

    /**
     * 异步线程将转码之后的内容（音频）写入到本地文件中
     * 如果将该部分的数据通过输出流输出那么就解决了
     */
    class AudioPublisher extends Publisher {

        private Process process;

        public AudioPublisher(Process process) {
            this.process = process;
            this.up = true;
        }

        public void run() {
            OutputStream outputStream = process.getOutputStream();
            while (!this.isInterrupted() && this.up) {

                try {
                    byte[] msg = peek(this);
//                    fos.write(msg);
//                    fos.flush();
//                    outputStream.write(msg);
//                    outputStream.flush();
                } catch (Exception ex) {
                    ex.printStackTrace();
                    break;
                }
            }

        }
    }
}
